`ifndef UART_SVH
`define UART_SVH

class uart_drive #(int baudrate);
    virtual uart_bfm #(.BAUDRATE (baudrate))  bfm;

    // rand byte data[];
    // constraint c
    // {
    //     data.size() == 5;
    //     foreach(data[i])
    //         data[i] inside {[1:255]};
    // }

    function new(virtual uart_bfm  #(.BAUDRATE (baudrate))  b);
        bfm = b;
    endfunction

    //virtual function byte calc_check(byte data[]);
    //endfunction

    /*
    * data_len, 数据帧长度, 可以是5位到8位
    * parity, 奇偶校验位, 0:无校验, 1:奇校验, 2:偶校验
    * 以奇校验位來說，如果给定一组数据位中1的个数是奇数，補一個bit为0，使得总的1的个数是奇数。
    *       例：0000001, 補一個bit为0, 00000010。
    * 以偶校验位來說，如果一组给定数据位中1的个数是奇数，補一個bit为1，使得总的1的个数是偶数。
    *       例：0000001, 補一個bit为1, 00000011。
    * stop_bit, 停止位, 0:1位, 1:1.5位, 2:2位
    */
    extern task settings(int data_len, int parity, int stop_bit);
    extern task write_byte(byte data);
    extern task write(byte data[]);
endclass

task uart_drive::settings(int data_len, int parity, int stop_bit);
    bfm.data_len = data_len;
    bfm.parity = parity;
    bfm.stop_bit = stop_bit;
endtask

task uart_drive::write(byte data[]);
    bfm.txd = 1;
    #100ns
    for(int i = 0; i < $size(data); i = i + 1 )
    begin
        write_byte(data[i]);
        #100ns;
    end
endtask

task uart_drive::write_byte(byte data);
    `ifdef PRINT_UART_INFO
        $display("uart master(bench) write 0x%x at %tns ", data, $time);
    `endif
    bfm.txd = 0; #(1s/baudrate);
    // data
    bfm.txd = data[0]; #(1s/baudrate);
    bfm.txd = data[1]; #(1s/baudrate);
    bfm.txd = data[2]; #(1s/baudrate);
    bfm.txd = data[3]; #(1s/baudrate);
    bfm.txd = data[4]; #(1s/baudrate);
    bfm.txd = data[5]; #(1s/baudrate);
    bfm.txd = data[6]; #(1s/baudrate);
    bfm.txd = data[7]; #(1s/baudrate);
    if(bfm.parity == 1)
    begin
        bfm.txd = ~(^data); #(1s/baudrate);
    end
    else if(bfm.parity == 2)
    begin
        bfm.txd = ^data; #(1s/baudrate);
    end
    // stop bit
    bfm.txd = 1; #(1s/baudrate);
endtask

`endif
